#include <stdio.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libgen.h>
#include <libxml/parser.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include "mosquitto.h"
#include "protocol.h"
/*
void *protocol_software_to_node(void *sft)
{
  GObject *software = sft;
  xmlNodePtr node = NULL;
  char buf[8], *str;
  int64_t id;

 // node = xmlNewNode(NULL, BAD_CAST "dev");
  node = xmlNewNode(NULL, BAD_CAST "root");
  g_object_get(software, "class", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "class", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(software, "typeDescribe", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "typeDescribe", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(software, "name", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "name", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(software, "id", &id, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, id);
  xmlNewProp(node, BAD_CAST "id", BAD_CAST buf);

  return node;
}
static int node_add_value(xmlNodePtr node, const char *name, GValue *value)
{
  char buf[8];

  if (G_VALUE_HOLDS_STRING(value)) {
    if (g_value_get_string(value))
    xmlNewProp(node, BAD_CAST name,
        BAD_CAST g_value_get_string(value));
  } else if (G_VALUE_HOLDS_INT(value)) {
    g_snprintf(buf, sizeof(buf), "%"G_GINT32_FORMAT, g_value_get_int(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_UINT(value)) {
    g_snprintf(buf, sizeof(buf), "%u", g_value_get_uint(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_LONG(value)) {
    g_snprintf(buf, sizeof(buf), "%ld", g_value_get_long(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_ULONG(value)) {
    g_snprintf(buf, sizeof(buf), "%lu", g_value_get_ulong(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_INT64(value)) {
    g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, g_value_get_int64(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_FLOAT(value)) {
    g_snprintf(buf, sizeof(buf), "%f", g_value_get_float(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_DOUBLE(value)) {
    g_snprintf(buf, sizeof(buf), "%f", g_value_get_double(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_BOOLEAN(value)) {
    g_snprintf(buf, sizeof(buf), "%d", g_value_get_boolean(value));
    xmlNewProp(node, BAD_CAST name, BAD_CAST buf);
  } else if (G_VALUE_HOLDS_POINTER(value)) {
    //printf("%p", g_value_get_pointer(value));
  } else {
    printf("Unknown type");
  }

  return true;
}
void *protocol_node_add(void *node, void *obj, const char *name)
{
  GObject *object = obj;
  xmlNodePtr self = node;

  GValue value = G_VALUE_INIT;
  g_object_get_property(object, name, &value);
  node_add_value(self, name, &value);
  g_value_unset(&value);
  return NULL;
}
void *protocol_device_to_node(void *dev)
{
  GObject *device = dev;
  xmlNodePtr node = NULL;
  gint status;
  char buf[8], *str = NULL;
  int64_t id;

  //node = xmlNewNode(NULL, BAD_CAST "dev");
  node = xmlNewNode(NULL, BAD_CAST "child");
  g_object_get(device, "class", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "class", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(device, "id", &id, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, id);
  xmlNewProp(node, BAD_CAST "id", BAD_CAST buf);
  g_object_get(device, "status", &status, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT32_FORMAT, status);
  xmlNewProp(node, BAD_CAST "status", BAD_CAST buf);
  g_object_get(device, "file1", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(device, "file2", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file2", BAD_CAST str);
    }
    free(str);
  }

  return node;
}
void *protocol_interface_to_node(void *ifa)
{
  GObject *interface = ifa;
  xmlNodePtr node = NULL;
  gint status;
  char buf[8], *chars;
  int64_t int64;
  gint int32;

  g_object_get(interface, "id", &int64, NULL);
  //node = xmlNewNode(NULL, BAD_CAST "dev");
  node = xmlNewNode(NULL, BAD_CAST "child");
  g_object_get(interface, "class", &chars, NULL);
  if (chars) {
    xmlNewProp(node, BAD_CAST "class", BAD_CAST chars);
    free(chars);
  }
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, int64);
  xmlNewProp(node, BAD_CAST "id", BAD_CAST buf);
  g_object_get(interface, "status", &status, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT32_FORMAT, status);
  xmlNewProp(node, BAD_CAST "status", BAD_CAST buf);
  g_object_get(interface, "update", &int32, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT32_FORMAT, int32);
  xmlNewProp(node, BAD_CAST "update", BAD_CAST buf);

  g_object_get(interface, "timestamp", &int64, NULL);
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, int64);
  xmlNewProp(node, BAD_CAST "timestamp", BAD_CAST buf);
  char *str = NULL;
  g_object_get(interface, "file1", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file1", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(interface, "file2", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file2", BAD_CAST str);
    }
    free(str);
  }

  return node;
}
char *protocol_time_str_from_timestamp(int64_t timestamp)
{
  char *time_str = NULL;
  GDateTime *dt = NULL;
  dt = g_date_time_new_from_unix_utc(timestamp+8*60*60);
  if (dt) {
    time_str = g_date_time_format(dt, "%Y-%m-%d %H:%M:%S");
    g_date_time_unref(dt);
  }
  return time_str;
}
void *protocol_point_to_node(void *pit)
{
  GObject *point = pit;
  xmlNodePtr node = NULL;
  char buf[16], *str;
  int64_t id, timestamp;
  gint status;
  bool has_file = false;

  g_object_get(point, "id", &id, "status", &status,
      "timestamp", &timestamp, NULL);
  //"file1", &file1, "file2", &file2, NULL);
  //node = xmlNewNode(NULL, BAD_CAST "dev");
  node = xmlNewNode(NULL, BAD_CAST "child");
  g_object_get(point, "class", &str, NULL);
  if (str) {
    xmlNewProp(node, BAD_CAST "class", BAD_CAST str);
    free(str);
  }
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, id);
  xmlNewProp(node, BAD_CAST "id", BAD_CAST buf);
  g_snprintf(buf, sizeof(buf), "%d", status);
  xmlNewProp(node, BAD_CAST "status", BAD_CAST buf);
  gint int32;
  g_object_get(point, "level", &int32, NULL);
  g_snprintf(buf, sizeof(buf), "%d", int32);
  xmlNewProp(node, BAD_CAST "level", BAD_CAST buf);
  g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, timestamp);
  xmlNewProp(node, BAD_CAST "timestamp", BAD_CAST buf);
  xmlNewProp(node, BAD_CAST "update", BAD_CAST "1");
  if (!timestamp) {
    timestamp = g_get_real_time()/(1000*1000);
  }
  g_object_get(point, "file2", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file2", BAD_CAST str);
    }
    free(str);
  }
  g_object_get(point, "file1", &str, NULL);
  if (str) {
    if (strlen(str) > 0) {
      xmlNewProp(node, BAD_CAST "file", BAD_CAST str);
      xmlNewProp(node, BAD_CAST "value", BAD_CAST str);
      has_file = true;
    }
    free(str);
  }
  GDateTime *dt = NULL;
  dt = g_date_time_new_from_unix_utc(timestamp+8*60*60);
  if (dt) {
    char *time_str = g_date_time_format(dt, "%Y-%m-%d %H:%M:%S");
    g_date_time_unref(dt);
    xmlNewProp(node, BAD_CAST "time", BAD_CAST time_str);
    g_free(time_str);
  } else {
    g_warning ("time error:%ld", timestamp);
  }
  if (!has_file) {
    if (status) {
      g_object_get(point, "valueStr", &str, NULL);
      if (str) {
        xmlNewProp(node, BAD_CAST "value", BAD_CAST str);
        free(str);
      } else {
        gboolean negation;
        float value, multiple, new_value;
        g_object_get(point, "value", &value, "multiple", &multiple,
            "negation", &negation, NULL);
        if (multiple != (float)(1.0)) {
          new_value = value*multiple;
        } else {
          new_value = value;
        }
        if (negation) {
          new_value = !new_value;
        }
        //g_snprintf(buf, sizeof(buf), "%.4f", value);
        //g_snprintf(buf, sizeof(buf), "%.4f", new_value);
        g_snprintf(buf, sizeof(buf), "%f", new_value);
        xmlNewProp(node, BAD_CAST "value", BAD_CAST buf);
      }
    }
  }
  return node;
}
void *protocol_interface_to_root_node(void *ifa)
{
  GObject *software = NULL;
  GObject *device = NULL;
  GObject *interface = ifa;
  xmlNodePtr sft_node = NULL, dev_node, ifa_node;

  g_object_get(interface, "parent", &device, NULL);
  g_object_get(device, "parent", &software, NULL);
  sft_node = protocol_software_to_node(software);
  dev_node = protocol_device_to_node(device);
  xmlAddChild(sft_node, dev_node);
  ifa_node = protocol_interface_to_node(interface);
  xmlAddChild(dev_node, ifa_node);
  return sft_node;
}
void *protocol_interface_to_root_node2(void *ifa, void **ifa_node_p)
{
  GObject *software = NULL;
  GObject *device = NULL;
  GObject *interface = ifa;
  xmlNodePtr sft_node = NULL, dev_node, ifa_node;

  g_object_get(interface, "parent", &device, NULL);
  g_object_get(device, "parent", &software, NULL);
  sft_node = protocol_software_to_node(software);
  dev_node = protocol_device_to_node(device);
  xmlAddChild(sft_node, dev_node);
  ifa_node = protocol_interface_to_node(interface);
  xmlAddChild(dev_node, ifa_node);
//  printf("[WARNING] ifa_node:%p\n", ifa_node);

  if (ifa_node_p)
    *ifa_node_p = ifa_node;
  return sft_node;
}
void *protocol_point_to_root_node(void *pit)
{
  GObject *interface = NULL;
  GObject *point = pit;
  xmlNodePtr sft_node = NULL, ifa_node, pit_node;
  bool update = false;

  g_object_get(point, "parent", &interface, "update", &update, NULL);
  if (!update) {
    return sft_node;
  }
  sft_node = protocol_interface_to_root_node2(interface, (void **)&ifa_node);
  pit_node = protocol_point_to_node(point);
  xmlAddChild(ifa_node, pit_node);
  g_object_set(point, "update", false, "level", false, NULL);

  return sft_node;
}
void *node_to_str(void *ptr)
{
  xmlNodePtr node = ptr;
  xmlBufferPtr xmlbuf = NULL;
  char *res = NULL;
  int rc;

  xmlbuf = xmlBufferCreate();
  rc = xmlNodeDump(xmlbuf, NULL, node, 1, 1);
  if (rc == -1) {
    printf("[WARNING] xmlnodedump error\n");
  } else {
    res = g_strdup((char *)xmlbuf->content);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  xmlFreeNode(node);
  return res;
}
void *protocol_point_to_str(void *pit)
{
  GObject *point = pit;
  xmlNodePtr sft_node = NULL;
  char *res = NULL;

  if (!pit) {
    return res;
  }
  sft_node = protocol_point_to_root_node(point);
  res = node_to_str(sft_node);
  return res;
}
void *protocol_interface_to_str(void *ifa)
{
  GObject *interface = ifa;
  GObject *point, *next;
  xmlNodePtr sft_node = NULL, ifa_node = NULL, pit_node = NULL;
  gboolean update = false;
  char *res = NULL;

  if (!ifa) {
    return res;
  }
  sft_node = protocol_interface_to_root_node2(interface, (void **)&ifa_node);
  g_object_get(interface, "son", &point, NULL);
  while (point) {
    g_object_get(point, "update", &update, NULL);
    if (update) {
      pit_node = protocol_point_to_node(point);
//      printf("[WARNING] ifa_node:%p pit_node:%p\n", ifa_node, pit_node);
      xmlAddChild(ifa_node, pit_node);
      g_object_set(point, "update", false, "level", false, NULL);
    }
    g_object_get(point, "next", &next, NULL);
    point = next;
  }

  res = node_to_str(sft_node);
  //return res;
  if (pit_node) {
    return res;
  } else {
    free(res);
    return NULL;
  }
}
void *protocol_device_to_str(void *obj)
{
  GObject *software = NULL;
  GObject *device = obj;
  GObject *interface = NULL, *interface_next;
  GObject *point, *point_next;
  xmlNodePtr sft_node = NULL, dev_node = NULL,
             ifa_node = NULL, pit_node = NULL;
  char *res = NULL;
  gboolean update;

  if (!obj) {
    return res;
  }
  g_object_get(device, "parent", &software, NULL);
  sft_node = protocol_software_to_node(software);
  dev_node = protocol_device_to_node(device);
  xmlAddChild(sft_node, dev_node);
  g_object_get(device, "son", &interface, NULL);
  while (interface) {
    ifa_node = protocol_interface_to_node(interface);
    xmlAddChild(dev_node, ifa_node);
    g_object_get(interface, "next", &interface_next,
        "son", &point, NULL);
    while (point) {
      g_object_get(point, "update", &update, "next", &point_next,
          NULL);
      if (update) {
        pit_node = protocol_point_to_node(point);
        xmlAddChild(ifa_node, pit_node);
        g_object_set(point, "update", false, "level", false, NULL);
      }
      point = point_next;
    }
    interface = interface_next;
  }

  res = node_to_str(sft_node);
  if (pit_node) {
    return res;
  } else {
    free(res);
    return NULL;
  }
}
void *protocol_software_all_to_str(void *obj)
{
  GObject *software = obj;
  GObject *device = NULL, *device_next;
  GObject *interface = NULL, *interface_next;
  GObject *point, *point_next;
  xmlNodePtr sft_node = NULL, dev_node = NULL, ifa_node = NULL, pit_node = NULL;
  char *res = NULL;

  if (!obj) {
    return res;
  }
  sft_node = protocol_software_to_node(software);
  g_object_get(software, "son", &device, NULL);
  while (device) {
    dev_node = protocol_device_to_node(device);
    xmlAddChild(sft_node, dev_node);
    g_object_get(device, "next", &device_next, "son", &interface, NULL);
    while (interface) {
      ifa_node = protocol_interface_to_node(interface);
      xmlAddChild(dev_node, ifa_node);
      g_object_get(interface, "next", &interface_next, "son", &point, NULL);
      while (point) {
        pit_node = protocol_point_to_node(point);
        xmlAddChild(ifa_node, pit_node);
        g_object_get(point, "next", &point_next, NULL);
        g_object_set(point, "update", false, "level", false, NULL);
        point = point_next;
      }
      interface = interface_next;
    }
    device = device_next;
  }

  res = node_to_str(sft_node);
  if (pit_node) {
    return res;
  } else {
    free(res);
    return NULL;
  }
}
void *protocol_device_get_mqtt(void *ptr)
{
  GObject *software = NULL;
  GObject *device = ptr;
  void *mqtt = NULL;

  g_object_get(device, "parent", &software, NULL);
  g_object_get(software, "intra", &mqtt, NULL);

  return mqtt;
}
void *protocol_object_get_mqtt(void *object, int depth)
{
  GObject *software = NULL, *device = NULL, *interface = NULL,
          *point = NULL;
  void *mqtt = NULL;

  if (depth == 3) {
    point = object;
  }
  if (point)
    g_object_get(point, "parent", &interface, NULL);
  if (depth == 2) {
    interface = object;
  }
  if (interface)
    g_object_get(interface, "parent", &device, NULL);
  if (depth == 1) {
    device = object;
  }
  if (device)
    g_object_get(device, "parent", &software, NULL);
  if (depth == 0) {
    software = object;
  }
  if (software)
    g_object_get(software, "intra", &mqtt, NULL);

  return mqtt;
}
void *protocol_interface_get_mqtt(void *ptr)
{
  GObject *software = NULL;
  GObject *device = NULL;
  GObject *interface = ptr;
  void *mqtt = NULL;

  g_object_get(interface, "parent", &device, NULL);
  g_object_get(device, "parent", &software, NULL);
  g_object_get(software, "intra", &mqtt, NULL);

  return mqtt;
}
void *protocol_point_get_mqtt(void *pit)
{
  GObject *software = NULL;
  GObject *device = NULL;
  GObject *interface = NULL;
  GObject *point = pit;
  void *mqtt = NULL;

  g_object_get(point, "parent", &interface, NULL);
  g_object_get(interface, "parent", &device, NULL);
  g_object_get(device, "parent", &software, NULL);
  g_object_get(software, "intra", &mqtt, NULL);

  return mqtt;
}
void *node_update_object(void *ptr, void *object)
{
  xmlNodePtr node = ptr;
  xmlChar *xml_char = NULL;
  xmlAttr *attr = NULL;
  GObject *obj_org = object, *obj;
  GObjectClass *obj_class = NULL;
  GParamSpec *pspec = NULL;
  gint64 id;

  xml_char = xmlGetProp(node, BAD_CAST "id");
  if (!xml_char) {
    printf("[WARNING] %s L%d f-%s no class\n", __FILE__, __LINE__, __func__);
    return NULL;
  }
  id = atoi((char *)xml_char);
  xmlFree(xml_char);
  obj = objects_get_object(obj_org, "id", &id);
  if (!obj) {
    return false;
  }
  obj_class = G_OBJECT_GET_CLASS(obj);
  const char *pro_name, *pro_value;
  for (attr = node->properties; attr; attr = attr->next) {
    xmlChar *value = xmlNodeGetContent(attr->children);
    //printf("L%d f-%s Property: %s, Value: %s\n", __LINE__, __func__,
     //   attr->name, value);
    pro_name = (char *)(attr->name);
    pro_value = (char *)value;
    pspec = g_object_class_find_property(obj_class, pro_name);
    if (pspec) {
      if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_STRING) {
        g_object_set(obj, pro_name, pro_value, NULL);
      } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT) {
        g_object_set(obj, pro_name, atoi(pro_value), NULL);
      } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_BOOLEAN) {
        g_object_set(obj, pro_name, atoi(pro_value), NULL);
      } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_INT64) {
        g_object_set(obj, pro_name, atoi(pro_value), NULL);
      } else if (G_PARAM_SPEC_VALUE_TYPE(pspec) == G_TYPE_FLOAT) {
        g_object_set(obj, pro_name, atof(pro_value), NULL);
      }
    }
    xmlFree(value);
  }
  GObject *son = NULL;
  xmlNode *child;
  g_object_get(obj, "son", &son, NULL);
  for (child = node->children; child; child = child->next) {
    if (child->type == XML_ELEMENT_NODE) {
      node_update_object(child, son);
    }
  }
  return obj;
}
bool protocol_update_object(const char *data, void *object)
{
  xmlDocPtr doc;
  xmlNodePtr root;

  doc = xmlParseDoc(BAD_CAST data);
  root = xmlDocGetRootElement(doc);
  node_update_object(root, object);

  xmlFreeDoc(doc);
  return true;
}
void *protocol_object_to_node(void *object, int depth, int flag)
{
  //flag 0:mutation 1:status
  xmlNodePtr node = NULL, nodeParent = NULL;
  GObject *self = object, *parent;
  char buf[16];//, *str;
  int64_t id;//, timestamp;
  gint status;

  if (flag) {//status
    g_object_get(self, "id", &id, "status", &status, NULL);
    if (depth) {
      g_object_get(self, "parent", &parent, NULL);
      nodeParent = protocol_object_to_node(parent, depth-1, flag);
      node = xmlNewNode(NULL, BAD_CAST "child");
    } else {
      node = xmlNewNode(NULL, BAD_CAST "root");
    }
    g_snprintf(buf, sizeof(buf), "%"G_GINT64_FORMAT, id);
    xmlNewProp(node, BAD_CAST "id", BAD_CAST buf);
    g_snprintf(buf, sizeof(buf), "%d", status);
    xmlNewProp(node, BAD_CAST "status", BAD_CAST buf);
    if (nodeParent) {
      xmlAddChild(nodeParent, node);
    }
  }
  return node;
}
void *protocol_status_to_str(void *object, int depth, int value)
{
  xmlNodePtr node = NULL, root = NULL;
  GObject *self = object;
  char *res = NULL;

  g_object_set(self, "status", value, NULL);
  node = protocol_object_to_node(object, depth, true);
  root = getRootNode(node);
  res = node_to_str(root);
  //free(res);res = NULL;
  return res;
}
void *protocol_offline(void *obj, int level)
{
  GObject *self = obj;
  char *res = NULL, topic[1024];
  int64_t id = 0;
  void *mqtt;
  int rc = 0;
  gint fa = false, tr = true;

  object_deep_set(obj, "status", &fa);
  object_deep_set(obj, "update", &tr);
  if (level == 1) {
    res = protocol_device_to_str(self);
    mqtt = protocol_device_get_mqtt(self);
  } else if (level == 2) {
    res = protocol_interface_to_str(self);
    mqtt = protocol_interface_get_mqtt(self);
  }
  if (res) {
    g_snprintf(topic, sizeof(topic),
        "3.1.2/%s/all/%"G_GINT64_FORMAT"/mutation",
        g_get_prgname(), id);
    rc = mosquitto_publish(mqtt, NULL, topic, strlen(res), res, 1, 0);
    if (rc != MOSQ_ERR_SUCCESS) {
      printf("[WARNING] %d", rc);
    } else {
      g_print("mqtt:----[%s]:\n%s\n", topic, res);
    }
    free(res);
  }
  return NULL;
}
*/
void *protocol__mqtt_init(void *obj)
{
  char *ip = "0.0.0.0";
  void *mqtt = NULL;
  int port = 1883, rc;

  mqtt = mosquitto_new(NULL, true, NULL);
  mosquitto_user_data_set(mqtt, obj);
  //mosquitto_disconnect_callback_set(mqtt, mqtt_disconnect_callback);
  //mosquitto_connect_callback_set(mqtt, mqtt_connect_callback);
  //mosquitto_message_callback_set(mqtt, mqtt_message_callback);
  while ((rc = mosquitto_connect(mqtt, ip, port, 60))) {
    printf("[WARNING] mqtt[%s]%d connect err:%d\t:%s, waiting 10 s\n",
        ip, port, rc, mosquitto_strerror(rc));
    sleep(10);
  }
  rc = mosquitto_loop_start(mqtt);
  if (rc) {
    printf("[WARNING] mqtt[%s]%d loop_start err:%d\t:%s\n",
        ip, port, rc, mosquitto_strerror(rc));
    return NULL;
  }
  printf("[DEBUG] mqtt[%s]%d connected\n", ip, port);
  return mqtt;
}
void *protocol__internal_mutation_broadcasting(void *obj,
    const char *frameId, const char *str)
{
  void *mqtt = obj;
  char topic[1024];
  int rc;

  snprintf(topic, sizeof(topic), "%s/%s/all/0/mutation",
      PROTOCOL_VERSION, frameId);
  rc = mosquitto_publish(mqtt, NULL, topic, strlen(str), str,
      1, 0);
  if (rc != MOSQ_ERR_SUCCESS) {
    printf("[WARNING] %s", mosquitto_strerror(rc));
  } else {
    printf("L%d f-%s [MQTT----][%s]:%s", __LINE__, __func__,
        topic, str);
   // pushStatus = true;
  }
  return NULL;
}
void *protocol_filtrateByXmlUpdate(void *node)
{
  xmlNodePtr rootNode = node, childNode, grandChildNode,
             greatGrandChildNode;
  xmlNodePtr root = NULL, child = NULL, grandChild = NULL,
             greatGrandChild = NULL;
  xmlChar *xml_char = NULL, *tmp_char = NULL;

  childNode = xmlFirstElementChild(rootNode);//device
  while (childNode) {
    xml_char = xmlGetProp(childNode, BAD_CAST "class");
    grandChildNode = xmlFirstElementChild(childNode);
    while (grandChildNode) {//interface
      greatGrandChildNode = xmlFirstElementChild(grandChildNode);
      while (greatGrandChildNode) {//point
        xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "update");
        if (!xml_char) {
          greatGrandChildNode = xmlNextElementSibling(
              greatGrandChildNode);
          continue;
        }
        if (strcmp((char *)xml_char, "1") == 0) {
          greatGrandChild = xmlNewNode(NULL, BAD_CAST "child");
          if (!grandChild) {
            grandChild = xmlNewNode(NULL, BAD_CAST "child");
            tmp_char = xmlGetProp(grandChildNode, BAD_CAST "id");
            if (tmp_char) {
              xmlNewProp(grandChild, BAD_CAST "id", tmp_char);
              xmlFree(tmp_char);
            }
            if (!child) {
              child = xmlNewNode(NULL, BAD_CAST "child");
              tmp_char = xmlGetProp(childNode, BAD_CAST "id");
              if (tmp_char) {
                xmlNewProp(child, BAD_CAST "id", tmp_char);
                xmlFree(tmp_char);
              }
              if (!root) {
                root = xmlNewNode(NULL, BAD_CAST "root");
                tmp_char = xmlGetProp(rootNode, BAD_CAST "id");
                if (tmp_char) {
                  xmlNewProp(root, BAD_CAST "id", tmp_char);
                  xmlFree(tmp_char);
                }
              }
              xmlAddChild(root, child);
            }
            xmlAddChild(child, grandChild);
          }
          xmlAddChild(grandChild, greatGrandChild);
          xmlFree(xml_char);
          xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "id");
          if (xml_char) {
            xmlNewProp(greatGrandChild, BAD_CAST "id", xml_char);
            xmlFree(xml_char);
          }
          xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "file1");
          if (xml_char) {
            xmlNewProp(greatGrandChild, BAD_CAST "file1", xml_char);
            xmlFree(xml_char);
          }
          xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "value");
          if (xml_char) {
            xmlNewProp(greatGrandChild, BAD_CAST "value", xml_char);
            xmlFree(xml_char);
          }
          xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "time");
          if (xml_char) {
            xmlNewProp(greatGrandChild, BAD_CAST "time", xml_char);
            xmlFree(xml_char);
          }
          xml_char = xmlGetProp(greatGrandChildNode, BAD_CAST "timestamp");
          if (xml_char) {
            xmlNewProp(greatGrandChild, BAD_CAST "timestamp", xml_char);
            xmlFree(xml_char);
          }
        }
        greatGrandChild = NULL;
        greatGrandChildNode = xmlNextElementSibling(
            greatGrandChildNode);
      }
      grandChild = NULL;
      grandChildNode = xmlNextElementSibling(grandChildNode);
    }
    child = NULL;
    childNode = xmlNextElementSibling(childNode);
  }
  return root;
}
char *protocol_nodeToStrWithoutFree(void *node)
{
  int rc;
  char *res = NULL;
  xmlNodePtr root = node;
  xmlBufferPtr xmlbuf = NULL;

  if (!node) {
    printf("[WARNING] no node\n");
    return NULL;
  }
  xmlbuf = xmlBufferCreate();
  rc = xmlNodeDump(xmlbuf, NULL, root, 1, 1);
  if (rc == -1) {
    printf("[WARNING] xmlnodedump error\n");
  } else {
    res = strdup((char *)xmlbuf->content);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  return res;
}
char *protocol_CopyNodeToStr(void *node)
{
  int rc;
  char *res = NULL;
  xmlNodePtr root = xmlCopyNode(node, 2), now = node;
  xmlNodePtr parent = now->parent;
  xmlBufferPtr xmlbuf = NULL;
  xmlChar *xml_char = NULL;
  xml_char = xmlGetProp(parent, BAD_CAST "file1");
  xmlSetProp(root, BAD_CAST "mapName", xml_char);

  if (!node) {
    printf("[WARNING] no node\n");
    return NULL;
  }
  xmlbuf = xmlBufferCreate();
  rc = xmlNodeDump(xmlbuf, NULL, root, 1, 1);
  if (rc == -1) {
    printf("[WARNING] xmlnodedump error\n");
  } else {
    res = strdup((char *)xmlbuf->content);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  xmlFreeNode(root);
  return res;
}
char *protocol_nodeToStr(void *node)
{
  int rc;
  char *res = NULL;
  xmlNodePtr root = node;
  xmlBufferPtr xmlbuf = NULL;

  if (!node) {
    printf("[WARNING] no node\n");
    return NULL;
  }
  xmlbuf = xmlBufferCreate();
  rc = xmlNodeDump(xmlbuf, NULL, root, 1, 1);
  if (rc == -1) {
    printf("[WARNING] xmlnodedump error\n");
  } else {
    res = strdup((char *)xmlbuf->content);
  }
  if (xmlbuf)
    xmlBufferFree(xmlbuf);
  xmlFreeNode(root);
  return res;
}
static xmlNodePtr getRootNode(xmlNodePtr node)
{
  while (node->parent != NULL) {
    node = node->parent;
  }
  return node;
}
/*
*/
static char *get_day()
{
  char res[64];
  time_t t = time(NULL);
  struct tm *tm_info = localtime(&t);
  int year = tm_info->tm_year + 1900;  // tm_year 从1900年开始
  int month = tm_info->tm_mon + 1;     // tm_mon 从0开始
  int day = tm_info->tm_mday;

  snprintf(res, sizeof(res), "%d-%02d-%02d", year, month, day);
  return strdup(res);
}
static char *get_date()
{
  time_t raw_time;
  struct tm *time_info;
  char formatted_time[20];

  time(&raw_time);
  time_info = localtime(&raw_time);
  strftime(formatted_time, sizeof(formatted_time),
      "%Y-%m-%d_%H:%M:%S", time_info);
  return strdup(formatted_time);
}
void *protocol__file_save(const char *res, size_t size,
    const char *frameId)
{
  char relative[128] = {0}, path[64] = {0}, filename[1024] = {0};
  char *day = get_day();
  char *date = get_date();
  char buf[1024], *dir;
  int ret;

  snprintf(path, sizeof path, "%s/%s/%d", frameId, day, 0);
  free(day);
  snprintf(relative, sizeof relative, "%s/%s.jpg",
      path, date);
  free(date);
  snprintf(filename, sizeof filename, "/mnt/%s", relative);
  dir = dirname(filename);
  if (access(dir, F_OK)) {
    snprintf(buf, sizeof(buf), "mkdir -p \"%s\"", dir);
    ret = system(buf);
    if (ret != 0)
      printf("[WARNING] create:%s failure", dir);
  }
  snprintf(filename, sizeof filename, "/mnt/%s", relative);
  FILE* file = fopen(filename, "w");
  if (file == NULL) {
    printf("[WARNING] can't open file: %s\n", filename);
    return NULL;
  }
  size_t bytes_written = fwrite(res, sizeof(char), size, file);
  if (bytes_written < strlen(res)) {
    printf("[WARNING] write failure\n");
  } else {
    printf("write %zu succeed\n", bytes_written);
  }

  fclose(file);
  return strdup(filename);
}
void *protocol__object_to_node(void *object, int depth, int flag)
{
  //flag 0:mutation 1:status
  xmlNodePtr node = NULL, nodeParent = NULL;
  xmlNodePtr now = object, parent = NULL;
  xmlChar *xml_char = NULL;

  if (flag) {//status
    if (depth) {
      parent = now->parent;
      nodeParent = protocol__object_to_node(parent, depth-1, flag);
      node = xmlNewNode(NULL, BAD_CAST "child");
    } else {
      node = xmlNewNode(NULL, BAD_CAST "root");
    }
    xml_char = xmlGetProp(now, BAD_CAST "id");
    if (xml_char) {
      xmlSetProp(node, BAD_CAST "id", xml_char);
      xmlFree(xml_char);
    }
    xml_char = xmlGetProp(now, BAD_CAST "status");
    if (xml_char) {
      xmlSetProp(node, BAD_CAST "status", xml_char);
      xmlFree(xml_char);
    }
    if (nodeParent) {
      xmlAddChild(nodeParent, node);
    }
  }
  return node;
}
void *protocol__status_to_str(void *object, int depth, int value)
{
  xmlNodePtr node = NULL, root = NULL;
  xmlNodePtr now = object;
  char *res = NULL, buf[8];

  snprintf(buf, sizeof(buf), "%d", value);
  xmlSetProp(now, BAD_CAST "status", BAD_CAST buf);
  node = protocol__object_to_node(object, depth, true);
  root = getRootNode(node);
  res = protocol_nodeToStr(root);
  //free(res);res = NULL;
  return res;
}
void *protocol__publish_status(const char *frameId, void *mqtt,
    void *obj, int depth, int status)
{
  int rc;
  int64_t id = 0;
  char topic[1024], *str = NULL;

  snprintf(topic, sizeof(topic),
      "%s/%s/all/%ld/status", PROTOCOL_VERSION, frameId, id);
  str = protocol__status_to_str(obj, depth, status);
  if (str) {
    rc = mosquitto_publish(mqtt, NULL, topic, strlen(str), str, 1, 0);
    if (rc != MOSQ_ERR_SUCCESS) {
      printf("[WARNING] %d", rc);
    } else {
      //g_debug("mqtt:----[%s]:\n%s\n", topic2, str);
    }
    free(str);
  }
  return NULL;
}

